/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#ifndef NODE_EXCEPTION_H_
#define NODE_EXCEPTION_H_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <iostream>
#include <string>
#include <exception>

namespace node {

    class Exception : public ::std::exception
    {
    public:
        Exception(void);
        explicit Exception(int code);
        Exception(const ::std::string& msg, int code);
        ~Exception(void);

        int code(void) const;
        const char* message(void) const;
        const char* what(void) const;

    private:
        int code_;
        ::std::string msg_;
    };

    inline int Exception::code(void) const
    {
        return code_;
    }

    inline const char* Exception::message(void) const
    {
        return msg_.c_str();
    }

    inline const char* Exception::what(void) const
    {
        return msg_.c_str();
    }

    inline ::std::ostream& operator << (::std::ostream& o, const Exception& e)
    {
        o << "****************************************************" << ::std::endl;
        o << "* Exception:" << ::std::endl;
        o << "*     code: " << e.code() << ::std::endl;
        o << "*     message: " << e.message() << ::std::endl;
        o << "****************************************************" << ::std::endl;
        return o;
    }

    //-------------------------------------------------------------------------
#define DECLARE_EXCEPTION_CODE(CLS, BASE, CODE)                                     \
    class CLS : public BASE                                                         \
    {                                                                               \
    public:                                                                         \
        CLS(int code = CODE);                                                       \
        CLS(const std::string& msg, int code = CODE);                               \
        ~CLS();                                                                     \
        CLS& operator = (const CLS& exc);                                           \
        const char* name() const;                                                   \
        const char* className() const;                                              \
    };

#define DECLARE_EXCEPTION(CLS, BASE) \
        DECLARE_EXCEPTION_CODE(CLS, BASE, 0)

#define IMPLEMENT_EXCEPTION(CLS, BASE, NAME)                                                        \
    CLS::CLS(int code) : BASE(code)                                                                 \
    {                                                                                               \
    }                                                                                               \
    CLS::CLS(const std::string& msg, int code) : BASE(msg, code)                                    \
    {                                                                                               \
    }                                                                                               \
    CLS::~CLS()                                                                                     \
    {                                                                                               \
    }                                                                                               \
    CLS& CLS::operator = (const CLS& exc)                                                           \
    {                                                                                               \
        BASE::operator = (exc);                                                                     \
        return *this;                                                                               \
    }                                                                                               \
    const char* CLS::name() const                                                                   \
    {                                                                                               \
        return NAME;                                                                                \
    }                                                                                               \
    const char* CLS::className() const                                                              \
    {                                                                                               \
        return typeid(*this).name();                                                                \
    }                                                                                                                                                                                           \


    DECLARE_EXCEPTION(LogicException, Exception)
    DECLARE_EXCEPTION(AssertionViolationException, LogicException)
    DECLARE_EXCEPTION(NullPointerException, LogicException)
    DECLARE_EXCEPTION(NullValueException, LogicException)
    DECLARE_EXCEPTION(BugcheckException, LogicException)
    DECLARE_EXCEPTION(InvalidArgumentException, LogicException)
    DECLARE_EXCEPTION(NotImplementedException, LogicException)
    DECLARE_EXCEPTION(RangeException, LogicException)
    DECLARE_EXCEPTION(IllegalStateException, LogicException)
    DECLARE_EXCEPTION(InvalidAccessException, LogicException)
    DECLARE_EXCEPTION(SignalException, LogicException)
    DECLARE_EXCEPTION(UnhandledException, LogicException)

}

#endif
